package com.rainman.simpleredis.core.delay_work;

import com.rainman.simpleredis.core.config.SimpleRedisConfig;
import com.rainman.simpleredis.core.distributed_lock.SimpleDistributedLock;
import com.rainman.simpleredis.core.scheduled.ScheduledInfo;
import com.rainman.simpleredis.core.scheduled.SimpleScheduled;
import com.rainman.simpleredis.core.scheduled.SimpleScheduledWorkerInterface;

import java.time.Duration;
import java.util.List;

/**
 * 延时任务
 * 基于redis键过期实现
 *
 */
public class SimpleDelayWorkService {


    private final SimpleRedisConfig simpleRedisConfig;
    private final SimpleDistributedLock simpleDistributedLock;

    private final Long rate=8000L;
    private final ScheduledInfo info=ScheduledInfo.buildRate(rate);

    public  final String DelayWorkTig;//SR0.Tig.DelayWork:
    public  final String DealLockHead="SimpleRedis.DelayDealOne:";

    public SimpleDelayWorkService(SimpleRedisConfig simpleRedisConfig
            , SimpleDistributedLock simpleDistributedLock
            , SimpleScheduled simpleScheduled
    ){

        this.simpleRedisConfig = simpleRedisConfig;
        this.simpleDistributedLock=simpleDistributedLock;

        String keyHead=simpleRedisConfig.getKeyHead()+ simpleRedisConfig.getProduct()+".";//SR0.
        DelayWorkTig =keyHead+"Tig.DelayWork:";//SR0.Tig.DelayWork:

        if(simpleRedisConfig.getSimpleDelayWorkDataInterface()==null){
            return;
        }

        simpleScheduled.addWorker(new SimpleScheduledWorkerInterface() {
            @Override
            public void doWork() {
                scanData();
            }

            @Override
            public String key() {
                return "SimpleDelayWork.ScanData";
            }

            @Override
            public ScheduledInfo info() {
                return info;
            }
        });

    }

    /**
     * 扫描之前数据
     * 与预加载下阶段数据
     */
    private void scanData(){

        Long cur=System.currentTimeMillis();

        Long maxTime=cur+(rate/2*3);

        List<SimpleDelayWorkMsgBean> simpleDelayWorkMsgBeans = simpleRedisConfig.getSimpleDelayWorkDataInterface()
                .notDealData(0L, maxTime);

        if(simpleDelayWorkMsgBeans ==null){
            return;
        }

        for(SimpleDelayWorkMsgBean msgBean: simpleDelayWorkMsgBeans){

            if(msgBean.getTigTime()<=cur){//之前的数据
                tig(msgBean.getId(),1L);
            }else {//之后的数据

                if(msgBean.getTigTime()<maxTime){
                    tig(msgBean.getId(),msgBean.getTigTime()-cur);
                }else {//一分钟之后的数据，等下一次处理
                    break;
                }

            }

        }

    }


    /**
     * 新增一个任务
     *
     * @param targetType 目标类型
     * @param targetId 目标id
     * @param targetInfo 目标信息
     * @param tigTime 触发时间
     * @return
     */
    public SimpleDelayWorkMsgBean addOne(String targetType,String targetId,String targetInfo,Long tigTime){
        if(simpleRedisConfig.getSimpleDelayWorkDataInterface()==null){
            throw new RuntimeException("该终端未实现持久化逻辑，不可新增延迟任务");
        }

        SimpleDelayWorkMsgBean simpleDelayWorkMsgBean = new SimpleDelayWorkMsgBean(targetType, targetId, targetInfo, tigTime);
        String id = simpleRedisConfig.getSimpleDelayWorkDataInterface().addData(simpleDelayWorkMsgBean);

        if(id==null||id.trim().length()<=0){
            throw new RuntimeException("持久化返回的唯一标识不正确");
        }
        simpleDelayWorkMsgBean.setId(id);

        Long delayMs=tigTime-System.currentTimeMillis();

        if(delayMs<=0){
            delayMs=1L;
        }

        if(delayMs>(rate/2*3)){//一分钟以后的不处理
            return simpleDelayWorkMsgBean;
        }
        tig(id,delayMs);

        return simpleDelayWorkMsgBean;
    }


    /**
     * 基于Redis键过期
     * 处理一条触发
     * @param key 触发的键
     */
    public void dealOne(String key) {//SR0.Tig.DelayWork:唯一id

        String[] split = key.split(":");
        String oriId=split[1];

        SimpleDelayWorkerInterface simpleDelayWorkerInterface = simpleRedisConfig.getSimpleDelayWorkerInterface();

        if(simpleDelayWorkerInterface==null){//没有执行器，不处理
            return;
        }


        //利用分布式锁，抢执行权
        Boolean aBoolean =simpleDistributedLock.dLockAdd(DealLockHead + oriId,40000L);
        if(!aBoolean){ return; }

        try{

            boolean needTigSure = simpleDelayWorkerInterface.doWork(oriId);

            if(needTigSure){
                simpleRedisConfig.getSimpleDelayWorkDataInterface().workSure(oriId);//发触发确认消息
            }

        }finally {
            simpleDistributedLock.dLockRemove(DealLockHead + oriId);

        }


    }

    private void tig(String id,Long dur){

        simpleRedisConfig.getRedisInterface().set(DelayWorkTig+id,"", Duration.ofMillis(dur));

    }


}
